/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * bocciawii is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * bocciawii is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bolas.h"

Bolas::Bolas()
{
	num_bolas = 0;
	bolas = new ElementoDinamico*[20];
}

Bolas::~Bolas()
{
	for (int i = 0; i < num_bolas; i++)
		bolas[i]->~ElementoEstacionario();
}

void Bolas::NuevaBola(ElementoDinamico* nueva_bola)
{
	bolas[num_bolas] = nueva_bola;
	num_bolas++;
	//std::cerr << "Bola recibida: " << bolas[num_bolas-1]->GetEquipo() << std::endl;
}

void Bolas::ReiniciarColisiones()
{
	for (int i = 0; i < num_bolas; i++)
	{
		bolas[i]->SetNoColisiona();
	}
}

void Bolas::GestionarColisiones()
{
	for (int i = 0; i < num_bolas; i++)
	{
		if (bolas[i]->EnMovimiento ())
		{
			for (int j = 0; j < num_bolas; j++)
			{
				if (bolas[j]->Lanzada()  && !bolas[j]->EnMovimiento ())
				{
					if (!bolas[j]->GetColision()) {
						if (bolas[i]->Distancia(bolas[j]) < 0.085) // Colision
						{
							float solapado = 0.085 - bolas[i]->Distancia(bolas[j]);
							bolas[i]->SetColisiona();
							bolas[j]->SetColisiona();

							float* posicion_bola1 = bolas[i]->GetPosicion();
							float* direccion_entrada = bolas[i]->GetDireccion();
							float velocidad_entrada = bolas[i]->GetVelocidadHorizontal();

							float* posicion_bola2 = bolas[j]->GetPosicion();
							float* nueva_direccion = new float[3];
							for (int k = 0; k < 3; k++)
							{
								nueva_direccion[k] = posicion_bola2[k] - posicion_bola1[k];
							}
							nueva_direccion = GetUnitario(nueva_direccion);

							int signo;
							int especial = 1;
							if (posicion_bola1[2] < posicion_bola2[2])
							    especial = -1;
							if (nueva_direccion[0] > 0 && direccion_entrada[0] > 0)
								signo = 1;
							if (nueva_direccion[0] < 0 && direccion_entrada[0] > 0)
								signo = -1;
							if (nueva_direccion[0] > 0 && direccion_entrada[0] < 0)
								signo = 1;
							if (nueva_direccion[0] < 0 && direccion_entrada[0] < 0)
								signo = -1;

							float coseno = fabs(nueva_direccion[0] * direccion_entrada[0] + nueva_direccion[2] * direccion_entrada[2]);
							float seno;

							if (1 - coseno < 0.01)
							{
								seno = 0;
								bolas[i]->Vel(0.25 * velocidad_entrada * bolas[i]->GetRestitucion() * bolas[j]->GetRestitucion(), 0);
								bolas[i]->Dir(-direccion_entrada[0], 1, -direccion_entrada[2]);
							}
							else if (coseno < 0.1)
							{
								seno = 1;
								coseno = 0;
								bolas[i]->Vel(velocidad_entrada * seno, 0);
								bolas[i]->Dir(direccion_entrada[0], 1, direccion_entrada[2]);
							}
							else
							{
								seno = sqrt(1 - pow(coseno, 2));
								if (seno < 0.01)
									seno = 0.0;

								float velocidad = velocidad_entrada * seno * bolas[j]->GetRestitucion();
								bolas[i]->Dir(especial * signo * nueva_direccion[2], 1, -signo * nueva_direccion[0]);
								bolas[i]->Vel(velocidad_entrada * seno * bolas[i]->GetRestitucion() * bolas[j]->GetRestitucion() * 0.5, 0);
							}


							//std::cerr << "Seno, coseno: " << seno << ", " << coseno << std::endl;

							/*std::cerr << "Datos de la colisión" << std::endl;
							std::cerr << "Posiciones iniciales" << std::endl;
							std::cerr << "Bola colisionadora: (" << posicion_bola1[0] << ", " << posicion_bola1[1] << ", " << posicion_bola1[2] << ")" << std::endl;
							std::cerr << "Bola colisionada: (" << posicion_bola2[0] << ", " << posicion_bola2[1] << ", " << posicion_bola2[2] << ")" << std::endl;

							//std::cerr << "Angulo de choque: " << angulo << std::endl;
							std::cerr << "Direccion de entrada: (" << direccion_entrada[0] << ", 1, " << direccion_entrada[2] << ")" << std::endl;
							std::cerr << "Nueva direccion: (" << nueva_direccion[0] << ", 1, " << nueva_direccion[2] << ")" << std::endl;
							std::cerr << "Nueva perpendicular: (" << signo * nueva_direccion[2] << ", 1, " << nueva_direccion[0] << ")" << std::endl;
							std::cerr << "Seno y coseno: " << seno << ", " << coseno << std::endl; 
							std::cerr << "Velocidad de entrada i: " << velocidad_entrada << std::endl;
							std::cerr << "Velocidad de salida i: " << bolas[i]->GetVelocidadHorizontal() << std::endl;
							*/

							bolas[j]->Dir(nueva_direccion[0], 1, nueva_direccion[2]);
							float velocidad_salida = fabs(velocidad_entrada * bolas[j]->GetRestitucion() * coseno * 0.5);
							bolas[j]->Vel(velocidad_salida, 0);
							bolas[j]->MoverIncremental(nueva_direccion[0] * solapado, 0, nueva_direccion[2] * solapado);
							//std::cerr << "Velocidad de salida j: " << velocidad_salida << std::endl;

						}
					}
				}
			}
		}
	}
}

int Bolas::EnMovimiento()
{
	int respuesta = 0;
	for (int i = 0; i < num_bolas; i++)
	{
		if (bolas[i]->EnMovimiento ())
		{
			respuesta = 1;
			//std::cerr << "Bola " << i << " se mueve" << std::endl;
		}
	}
	return respuesta;

}

void Bolas::ActualizarPosicion(int delta) 
{
	for (int i = 0; i < num_bolas; i++)
	{
		if (bolas[i]->Lanzada() && bolas[i]->EnMovimiento ())
			bolas[i]->ActualizarPosicion (delta);
		ReiniciarColisiones ();
	}
}

void Bolas::Dibujar()
{
	for (int i = 0; i < num_bolas; i++)
	{
		if (bolas[i]->Lanzada ())
			bolas[i]->Dibujate();
	}
}

void Bolas::Limpiar()
{
	for (int i = 0; i < num_bolas; i++)
	{
		bolas[i]->~ElementoDinamico();
	}
	num_bolas = 0;
}

float Bolas::DistanciaBlanca(ElementoDinamico* _bola)
{
	return _bola->Distancia(bolas[0]);
}

ElementoDinamico* Bolas::MasCercana()
{
	float distancia = 25;
	ElementoDinamico* bola_cercana = NULL;

	for (int i = 1; i < num_bolas; i++)
	{
		if (bolas[i]->Lanzada()) 
		{
			float nueva_distancia = DistanciaBlanca(bolas[i]);
			if (nueva_distancia < distancia)
			{
				distancia = nueva_distancia;
				bola_cercana = bolas[i];
			}
		}
	}
	return bola_cercana;
}